package n8_设计模式_保护性暂停;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

import static utils.Sleeper.sleep;

/**
 * ----------------------------------------------------------------------
 * |                                                                    |
 * |     保护性暂停，添加 等待超时时间                                      |
 * |                                                                    |
 * |=====================================================================
 */
@Slf4j(topic = "c.T2")
public class T2_Guarded_Timeout {

    // [t1线程]  等待  [t2线程] 的下载结果
    public static void main(String[] args) {

        final GuardedDe guarded = new GuardedDe();

        // 1. 等待结果
        new Thread(()->{
            log.debug("等待结果...");
            final List<String> list = (List<String>) guarded.get(3000);

            log.debug("结果大小：{}",  list == null ? null :  list.size());

        }, "t1").start();

        new Thread(()->{

            log.debug("开始下载...");
            try {

// HEAD >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                // 虚假唤醒
                sleep(1);
                guarded.complete(null);

// =======================================================
//                sleep(1);
//                guarded.complete(Arrays.asList(new String[]{"2","3"}));

// END  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

            } catch (Exception e) {
                e.printStackTrace();
            }


        }, "t2").start();

    }

}

class GuardedDe{

    private Object response = null;

    // 获取
    public Object get(long timeout){

        synchronized (this){
            // 开始时间
            long begin = System.currentTimeMillis();
            // 经历时间
            long passedTime = 0;

            while(response == null){

                final long surplusWaitTime = timeout - passedTime;  // 还需 等待时间

                // 如果超时，退出
                if(surplusWaitTime <= 0)break;

                try {
                    /*---------------------------------------------------------------------
                    |                                                                     |
                    |     注意：这里wait [不能填写 timeout] ，防止虚假唤醒，重置等待时间        |
                    |                                                                    |
                    |====================================================================*/
                    this.wait(surplusWaitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                // 计算经历时间
                passedTime = System.currentTimeMillis() - begin;
            }
        }
        return this.response;
    }

    // 产生结果
    public void complete(Object res){

        synchronized (this){

            this.response = res;
            this.notifyAll();
        }

    }

    /*---------------------------------------------------------------------
    |                                                                     |
    |        上面 get() 方法 与 下面的 Thread.join(long millis) 逻辑相似     |
    |        即： 也使用了 【保护性暂停】模式                                |
    |====================================================================
    public final synchronized void join(long millis)
            throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;  // 需要等待时间
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;  // 已经等待时间
            }
        }
    }

     */

}
